package com.yfbao.horizon.pay.utils;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import javax.validation.constraints.NotBlank;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MD5SignUtil {


    public static void main(String[] args) {
//        String params = "amount=1.00&callbackUrl=https://wx.yuansfer.yunkeguan.com/wx&currency=USD&goodsInfo=[{\"goods_name\":\"Yuansfer\",\"quantity\":\"1\"}]&ipnUrl=https://wx.yuansfer.yunkeguan.com/wx&merchantNo=200043&reference=seq_1525922323&settleCurrency=USD&storeNo=300014&terminal=ONLINE&timeout=120&vendor=alipay";
//        String token = "5cbfb079f15b150122261c8537086d77";
//        String tokenMd5 = DigestUtils.md5Hex(token);
//        System.out.println(tokenMd5);
//
//        String signStr = params+"&"+tokenMd5;
////        String signStr = params+"&token="+tokenMd5;
//        String sign = DigestUtils.md5Hex(signStr);
//        System.out.println(sign);

        SecurePayDto payDto = new SecurePayDto();
        payDto.setMerchantNo("204559");
        payDto.setStoreNo("304686");
        payDto.setAmount("1.00");
        payDto.setCurrency("CNY");
        payDto.setSettleCurrency("USD");
        payDto.setVendor("alipay");
        payDto.setIpnUrl("https://wx.yuansfer.yunkeguan.com/wx");
        payDto.setCallbackUrl("https://wx.yuansfer.yunkeguan.com/wx");
        payDto.setReference("seq_1525922323");
        payDto.setTerminal("ONLINE");
        payDto.setOsType("IOS");
        payDto.setGoodsInfo("[{\"goods_name\":\"Yuansfer\",\"quantity\":\"1\"}]");

// 商户密钥
        String secretKey = "18294606a68312f75e9c65a364361c02";

// 生成签名
        String sign = MD5SignUtil.generateSign(payDto, secretKey);
//        payDto.setVerifySign(sign);
        System.out.println("加签结果："+sign);

// 验证签名
//        boolean isValid = MD5SignUtil.verifySign(payDto, secretKey, sign);
//        System.out.println("签名验证结果: " + isValid);

    }

    /**
     * 生成签名
     * @param obj 包含请求参数的对象
     * @param apiToken API令牌
     * @return MD5签名(大写)
     */
    public static String generateSign(Object obj, String apiToken) {
        try {
            // 1. 获取所有非空字段的key=value对
            List<String> paramPairs = getNonNullFieldPairs(obj);
            for (String paramPair : paramPairs) {
                System.out.println(paramPair);
            }
            // 2. 按参数名字母顺序排序
            Collections.sort(paramPairs);
            System.out.println("---------------------------------------");
            for (String paramPair : paramPairs) {
                System.out.println(paramPair);
            }
            // 3. 用&连接所有参数
            String concatenatedParams = String.join("&", paramPairs);
            System.out.println(concatenatedParams);
            // 4. 计算API token的MD5
            String md5ApiToken = DigestUtils.md5Hex(apiToken);
            // 5. 拼接最终字符串
            String finalString = concatenatedParams + "&" + md5ApiToken;
            // 6. 计算最终MD5并转为大写
            return DigestUtils.md5Hex(finalString);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("生成签名失败", e);
        }
    }

    /**
     * 验证签名
     * @param obj 包含请求参数的对象
     * @param apiToken API令牌
     * @param signToVerify 待验证的签名
     * @return 是否验证通过
     */
    public static boolean verifySign(Object obj, String apiToken, String signToVerify) {
        if (StringUtils.isEmpty(signToVerify)) {
            return false;
        }
        String calculatedSign = generateSign(obj, apiToken);
        return signToVerify.equalsIgnoreCase(calculatedSign);
    }

    /**
     * 获取对象中所有非空字段的key=value对列表
     */
    private static List<String> getNonNullFieldPairs(Object obj) throws IllegalAccessException {
        List<String> pairs = new ArrayList<>();
        Field[] fields = obj.getClass().getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);
            Object value = field.get(obj);
            if (value != null && !StringUtils.isEmpty(value.toString())) {
                pairs.add(field.getName() + "=" + value);
            }
        }
        return pairs;
    }




}
